﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Linq;
namespace Cyss.Core
{
    public static class BaseSearchModelExpressionHelper
    {

        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="Name"></param>
        /// <returns></returns>
        private static object GetValue(this object obj, string Name)
        {
            var value = obj.GetType().GetProperty(Name).GetValue(obj);
            return value;
        }


        /// <summary>
        /// 通过Lambda解析为Sql
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public static List<string> GetFields(Expression func)
        {
            List<string> fields = new List<string>();
            if (func == null)
            {
                return fields;
            }
            if (func.NodeType == ExpressionType.Lambda)
            {
                func = func.GetValue("Body") as Expression;
            }
            var funcType = CheckExpressionType(func);
            switch (funcType)
            {
                case EnumNodeType.MemberAccess:
                    fields.Add(VisitMemberAccessExpression(func as MemberExpression));
                    break;
                case EnumNodeType.New:
                    fields.AddRange(VisitNewExpression(func as NewExpression));
                    break;
                case EnumNodeType.UndryOperator:
                    fields.Add(VisitUnaryExpression(func as UnaryExpression));
                    break;
                default:
                    throw new NotSupportedException("");
            }
            return fields.Distinct().ToList();
        }

        /// <summary>
        /// 判断包含变量的表达式
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        private static string VisitMemberAccessExpression(MemberExpression func)
        {
            return func.Member.Name;
        }
        /// <summary>
        /// 判断包含变量的表达式
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        private static string VisitUnaryExpression(UnaryExpression func)
        {
            var funcType = CheckExpressionType(func.Operand);
            switch (funcType)
            {
                case EnumNodeType.MemberAccess:
                    return  VisitMemberAccessExpression(func.Operand as MemberExpression);
                default:
                    throw new NotSupportedException("");
            }
        }

        private static List<string> VisitNewExpression(NewExpression exp)
        {
            List<string> fields = new List<string>();
            foreach (var Argument in exp.Arguments)
            {
                fields.AddRange(GetFields(Argument));
            }
            return fields;
        }


        /// <summary>
        /// 判断表达式类型
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        private static EnumNodeType CheckExpressionType(Expression func)
        {

            switch (func.NodeType)
            {
                case ExpressionType.AndAlso:
                case ExpressionType.OrElse:
                case ExpressionType.Equal:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.LessThan:
                case ExpressionType.NotEqual:
                    return EnumNodeType.BinaryOperator;
                case ExpressionType.Constant:
                    return EnumNodeType.Constant;
                case ExpressionType.MemberAccess:
                    return EnumNodeType.MemberAccess;
                case ExpressionType.Call:
                    return EnumNodeType.Call;
                case ExpressionType.MemberInit:
                    return EnumNodeType.MemberInit;
                case ExpressionType.Not:
                case ExpressionType.Convert:
                    return EnumNodeType.UndryOperator;
                case ExpressionType.New:
                    return EnumNodeType.New;
                default:
                    return EnumNodeType.Unknown;
            }
        }

    }

    public enum EnumNodeType
    {
        /// <summary>
        /// 二元运算符
        /// </summary>
        BinaryOperator = 1,

        /// <summary>
        /// 一元运算符
        /// </summary>
        UndryOperator = 2,

        /// <summary>
        /// 常量表达式
        /// </summary>
        Constant = 3,

        /// <summary>
        /// 成员（变量）
        /// </summary>
        MemberAccess = 4,

        /// <summary>
        /// 函数
        /// </summary>
        Call = 5,


        /// <summary>
        /// 不支持
        /// </summary>
        MemberInit = 6,


        New = 7,

        /// <summary>
        /// 未知
        /// </summary>
        Unknown = -99,

        /// <summary>
        /// 不支持
        /// </summary>
        NotSupported = -98


    }
}
